/* ccscript parser */
#pragma once

#include <boost/shared_ptr.hpp>
#include <string>
#include <map>
#include <vector>

#include "lexer.h"

class Parser;

class Node;
class Statement;
class Expression;
class Program;
class IfExpr;
class MenuExpr;
class CommandDef;
class ConstDef;



struct ParseSymbol
{
	// Reference-counted pointers for convenience
	typedef boost::shared_ptr<ParseSymbol> Ptr;

	ParseSymbol(const std::string& value, Parser* parser)
		: value(value), parser(parser),
		  has_nud(false), has_led(false), has_std(false) {   }
	ParseSymbol(const std::string& value, int lbp, Parser* parser)
		: lbp(lbp), value(value), parser(parser),
		  has_nud(false), has_led(false), has_std(false){   }
	ParseSymbol(const std::string& value, int lbp, const std::string& arity, Parser* parser)
		: lbp(lbp), value(value), arity(arity), parser(parser),
		  has_nud(false), has_led(false), has_std(false) {   }

	// Returns a new-allocated copy of this symbol
	virtual ParseSymbol* clone() const {
		return new ParseSymbol(value, lbp, arity, parser);
	}
	// Null denotation parsing
	virtual Expression* nud();
	// Left denotation parsing
	virtual Expression* led(Expression* left);
	// Statement denotation parsing
	virtual Statement* std();

	// Attributes
	Parser* parser;			// Parser for this symbol

	int lbp;				// left binding power
	std::string value;		// token string value
	std::string arity;		// symbol arity (NOTE: should probably be renamed "type" --
							//  is used for more than just param count, e.g., "literal", "name", etc.
							//  strictly speaking the arity of those things would be zero.

	bool has_nud;			// True iff this symbol has a null denotation
	bool has_led;			// True iff this symbol has a left denotation
	bool has_std;			// True iff this symbol has a statement denotation

	// Error reporting
	int line;				// Source line on which this symbol occurs
	void Error(const std::string& msg) const;
};



/*
 * A simple recursive descent parser based on ccscript's LL(2) grammar.
 * Verifies that a program is derivable under the grammar, and if so,
 * produces an abstract syntax tree representation of the program.
 */
class Parser
{
public:
	// Constructs a parser for the given source string
	explicit Parser(const std::string& src);
	//
	// Parses a complete program
	Program* Parse();
	//
	// Parses an returns a single expression
	Expression* ParseExpression();
	//
	// Sets the object that will receive any parse errors
	void SetErrorHandler(ErrorReceiver*);
	//
	// Gets the error handler previously set by SetErrorHandler
	ErrorReceiver* GetErrorHandler() const;

	
	
	int line;
	
private:
	Lexer *lexer;

	ErrorReceiver* error;

public:
	void Error(const std::string &msg, int line);
	void Warning(const std::string &msg, int line);


	// New stuff
public://TEMP
	class SymbolTable
	{
	public:
		SymbolTable();
		void define_name(ParseSymbol* sym);	// might not use this
		void define_op(ParseSymbol* sym);
		ParseSymbol* find(const std::string &name) const;
	public:
		SymbolTable* parent;
	private:
		std::map<std::string, ParseSymbol*> table;
	};

	SymbolTable* scope;

	void init();			// Initializes the parser
	void push_scope();		// Pushes a new scope onto the stack
	void pop_scope();		// Removes the top scope from the stack

	ParseSymbol::Ptr token;	// Current token

	ParseSymbol::Ptr advance();
	ParseSymbol::Ptr advance(const std::string& expected,
		const std::string& err_message);

	// Production rules
	Expression* expression(int rbp);
	Statement* statement();
	Statement* statements();

};

